import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

/*
 * STEI03 - Ten thousand
The game Ten Thousand, is played as follows (by one or more players): 
You throw five dice. Each 1 you get gives you a hundred, each 5 gives fifty. 
If you get three of the same kind in a single throw, you get a hundred times that number, 
except in the case of three 1s, which gives a thousand. 
Four of the same kind gives twice what three give, and five of the same gives four times that.
(for example, getting four 3s gives 600 and five 3s gives 1200). 
If you get some points in the first throw (with five dice) you can keep some or all of the dice that gave points 
and throw the remaining ones again. This also applies to all successive throws; 
as long as you get any points in a throw you can throw again, provided you keep some of the dice that gave points. 
If you get points for all the dice you throw you can then throw all five dice again. 
You can stop throwing at any time and collect the points you have accumulated.
 If you get no points in a throw, you lose all points accumulated in that series of throws. 
 Find the optimal strategy for this game.
 */

/**
 * @author Stephen Dolman, 200907049
 *
 * 29.10.12 - Started working in this class. It runs, and generates...not a lot. Tries to print out die rolls, but bugs out.
 * 31.10.12 - Met with the Prof today re. project spec. Motivated me enough to think I should try and fix die rolling.
 * 			  And, it's fixed now! Turns out I was using array.toString() wrongly. 
 * 		      Maybe there's a more elegant way to print out rolls, but IDC, nobody's gonna see the command line when I'm done.
 * 05.11.12 - Been a week now; I should really start some real work on this. Started working blindly on how to evaluate a throw's score.
 * 			  But it proved difficult - if, say you roll 33213, my method was a little dodgy at noticing that there's 3 3s in that roll.
 * 		      So instead, I spent today trying out a few different algorithms of organising rolls to make calculation easier.
 * 			  My plan is to sort the rolls numerically, and then transpose the sorted rolls to an array of counts; not values.
 * 			  ie, example roll 33123 becomes 113000, because there's 1 1, 1 2, 3 3s etc. This should make it easier to spot dubs and trips.
 * 			  But we'll see.
 * 06.11.12 - Yesterday's session was addictive, so I'm back today to try and score the throws.
 * 			  Thus far; have written the 33123->113000 method prescribed yesterday.
 * 16.01.13 - Bulk of the work today was setting up an SVN repository.
 * 18.01.13 - SVN operational here and in uni.
 * 			  Now working on die subbing and general "stuff you can do in a turn".		
 * 21.01.13a- Wow, my notes of what I do in a session are getting kind of short.
 * 			  Last time I'd started too many things at once - rerolling, partial rerolling and general bug fixes, 
 * 			  and nothing got properly done as a result.
 * 			  Having mulled over the reroll psuedocode over the weekend, today I have a much better idea of how to reroll, and when to note down scores to decide when a reroll is a bad move and might lose 
 * 			  all your points.
 * 21.01.13b- Discovered that my scoring method has a few gaping holes; but since they're quite obvious to fix, I'll leave them for now.
 * 27.01.13 - Worked on a 'remover' method that, when the user wants to reroll some die, plucks out the ones of their choosing to get rid of.
 * 			  Fixed the scoring method at long last.
 *03+04/02/13-Or so I thought! *NOW* the die scorer is 100% foolproof. It's not particularly elegant, but it's neater than listing 11111 = 4k, 11112 = 2k, 11113 = 2k....etc, in a forced and 'binary' fashion.
 * 			  Today's big hurdle is trying to properly get die 'removal' and rerolling done. Currently, as detailed below, sometimes 2 of the same value can be removed at once, and they shouldn't in short.
 *			  NB, rerolling doesn't yet check *if* a player scored before allowing a (partial) reroll, but that relies on having a multi-player system anyway, and it won't take much imagination to do then.
 * 04.02.13 - Today was a pretty great day so far. Die rerolling works like a charm, and the scoring mechanism works great too. The program now tells the user when a reroll is worth more or less than 
 * 			  the last roll; the next main step is to have the reroller employ a user-requested recursive call when a reroll is successful and they'd like to risk another.
 * 05.02.13 - Turns out I'd implemented scoring wrongly; triplets have to be cast in a single throw. Makes the calculations easier to do in the long run,
 * 			  but it means a substantial method rewrite is required.
 * 20.03.13 - Forgotten to update this history for what feels like a lifetime - hope I can use my weekly reports as a history log instead...
 * 			  In my absence from this wall of cerulean, the program has evolved beyond recognition. The full game has long since been playable (finished round about the start of March).
 * 			  The "winning strategy" automated play mode has also been in full swing for about 3 weeks, and has gone through many iterations since then.
 * 			  Now, in I presume its last form, it logs Ys and Ns to a text file after debating the finer points of strategy with itself through many trials.
 * 			  Today, I started work on a simple GUI for the benefit of demonstration as much as anything else. Quite a task considering my past inadequacy in the field...
 * 21.03.13	- Primitive GUI is operational; it takes in numbers and the occasional (y/n) choice and performs actions based on them.
 * 			  Many more user tests were conducted today (13/19) now that the GUI makes things easier. Feedback's been great, who knew people would be so impressed with a text pane.
 * 			  Program doesn't handle erroneous input well - but this is a minor issue compared with how little report is done. Looks like this is the end of coding!
 * 25.03.13 - Adding a ton of comments to constructors and such...not that there weren't many before.
 */

//~~~NOTE TO SELF~~~ - can't connect with Repo from library, remember to Commit once you get home!

public class Main {
	
	static int totalScore = 0;	//This holds the total score for the game. Will eventually be moved to a "player" class, once I make one.
	static int scoreForThisTurn = 0; //In order to be able to "re-roll" some of the die to maximise score, one needs to have had a score on that round to begin with.
									 //That's why this exists - to check if we did score on any given round. This is pre-re-roll.
	static int modifiedScoreForThisTurn = 0;	//...and this is post-re-roll! Any discrepancy between the values means the reroll scored something, lack of discrepancy voids the turn.
	static int turnsTakenThusFar = 0;			//To add a competitive edge, or just for curiosty's sake, this increments each phase by 1. Each player will have their own.
	static ArrayList<Integer> vals;	//The vals arrayList holds the value of each die's roll. When you roll the die, they'll show up in here.
	static ArrayList<Integer> lastGo = null;	//As soon as die are rolled, however, they're moved to lastGo. This is a necessary step for when die are rerolled.
	static Boolean on = true;					//This is so that the main "loop" of the game runs. Do not modify anywhere plz.
	//static Scanner sc = new Scanner(System.in); //Once used for user choices. Removed when GUI was operational.
	static DiceSack d = new DiceSack();			//The dicesack contains our 5 die. It's like the cup in Yahtzee, etc.
	static Boolean canReroll = false;			//	This stops us doing a reroll when we shouldn't.
	static int theVeryLatestScore = 0;			// Does what it says on the tin - stores the very latest score of the current turn, as opposed to total game score so far.
	static ArrayList<Integer> diceToReroll = new ArrayList<Integer>();		//For reroll scoring. We can't use the main dice array, or dice of the same value attained over successive throws would be lumped together.
												//5 one turn and two more the following throw =/= 5 in the same throw, for example.
	static float[][] earnings = new float[5][201]; //Each cell stores how many points each maneuver is worth in Sim Mode.
	static float[][] attempts = new float[5][201]; //Unused array; used to work out average points-per-maneuver.
	
	static int maxScorein1Turn = 0; //Used to track where users go right in a game. 
	static boolean punishLoser; //Boolean used to end each simulation in Sim Mode.
	
	//GUI Initialisations
	static String userSelection = null; //Important String! Whenever this String is set to null, the program halts, waiting for user input.
										//WHen this String becomes "not null", the program reads this string, acts upon the input, and sets it back to null to "wait" for more.
	static JFrame window; //Layout container. Nothern components, ie output, are stuck in this window.
	static JPanel southWindow; //Layout container. Input-related components are to appear at the bottom of the GUI. Meant to imitate the style of the Eclipse UI in the ol' days.
	static JScrollPane jsp; //Allows a scroll bar to appear in the output window. Stops the program crashing after 2-odd turns. :)
	static JLabel inputLabel; //Simply points users to where they are to type input.
	static JTextArea output; //The output window is a one-way JTextArea that output Strings, eg dice rolls, are "echo"ed onto.
	static JTextField input; //Separate from the output window to reduce confusion and allow simultaneous display of output+potential input.
	static String nL = "\n";  //Used to add a new line to the end of Strings appended to the user interface, since support for new lines seems limited/fiddly.
	//End of GUI stuff
	
	public static void main (String[] args){
		
		createAndShowGUI();
		
		output.append("Are you wanting to play a game (a); or enter Simulation Mode to loop a number of experiments? (b)" + nL +nL); 
		//output.append sends the parameter to the (end of the) GUI output window.
		
		while(userSelection==null){ 
		 /**In case you wonder what the few "empty" loops do throughout the program, well...
		 ..they're to make the program halt while it's waiting for user input.
		 Since userSelection is where input is stored, it works out perfectly.*/
		}
		
		if(userSelection.equals("a")){ //Game mode is entered upon hitting a.
			userSelection = null; //Setting this to null means "I'm gonna wait on user input now".
			while(on==true){
				userSelection = null;
				output.append("=================SELECT AN OPTION TO PLAY=================="+nL); //Main menu sent to GUI screen. I like to think each function's obvious from the name.
				output.append("1:                                       Roll all die and display score!"     +nL);
				output.append("2:                                           Reroll all worthless die!                "+nL);
				output.append("5:                                   Display worthless die from last roll!"          +nL  );
				output.append("7:                        Print current game info (Total score and turns transpired)"+nL);		
				output.append("10:                                          Display game rules"+nL);
				output.append("999:                                                  Quit"+nL+nL);
				
				while(userSelection==null){ 
					//Another "wait on user" stall loop.
				}
					
				int choosy = Integer.parseInt(userSelection); //User's choice from above menu! Since userSelection is a String, we parse it for an int. Doesn't like being fed junk.
				output.append(nL+choosy+nL); //Users might like reminded what they typed.
				
				switch(choosy){
				
				case 1:		turnsTakenThusFar++;  //What happens when you hit roll Die.
							vals = d.rollEach();
							theVeryLatestScore = scorerAlgorithm(valueTransposer(vals));
							if(theVeryLatestScore>maxScorein1Turn){
								maxScorein1Turn = theVeryLatestScore;
							}
							output.append("You rolled: "+"["+vals.get(0)+"] "+"["+vals.get(1)+"] "+"["+vals.get(2)+"] "+"["+vals.get(3)+"] "+"["+vals.get(4)+"] for a score of "+theVeryLatestScore+"."+nL);
							totalScore = totalScore+theVeryLatestScore;
							lastGo =  (ArrayList<Integer>) vals.clone();
							vals.clear();
							canReroll = true;
							if(theVeryLatestScore==0){
								canReroll=false;
							}
							if(diceToReroll.size()>0){
								diceToReroll.clear();
							}
							winTest();
							if(worthlessDice().size()==0){
								output.append("Congratulations! Since all dice scored, you can roll all the dice again to enhance the score further..."+nL);
								output.append("Want to risk it? (y/n)"+nL+nL);
								userSelection = null;
								
								while(userSelection==null){
								}
								
								if(userSelection.equals("y")){
									lastGo.clear();
									specialAllScoreRerollCase();
								}
							}
							userSelection = null;
							break;
					
				case 2:	if(canReroll==true){  //"Reroll dice" code. Can only be entered when the user rolled just there, and got some points.
						whatToDoWhenRerolling();
						canReroll = false;
						}
						else{
							output.append(nL+"You can't reroll now; since you either re-rolled just there and stopped, didn't score on the last roll, or haven't rolled yet!"+nL+nL);
						}
						winTest();
						break;

				case 5:	output.append(nL+"The worthless die are: "+worthlessDice()+nL+nL); //Quick calc 'n' display of which die are "worthless" to a combination.
						break;
					
				case 7: output.append(""+turnsTakenThusFar+" turns have been taken thus far."+nL); //Displays some game info.
						output.append("The total score so far is "+totalScore+"."+nL+nL);
						break;
						
						
				case 10: //The rules! Not hard to work out what's going on here.
						 output.append(nL+"Ten Thousand is a 5-dice game, the objective of which is to reach 10,000 points in as few turns as possible."+nL+nL);
						 output.append("Dice are scored as follows:"+nL);
						 output.append("A single [1] is worth 100 points, and a single [5] is worth 50."+nL);
						 output.append("A triplet (3 of a kind in a single throw) of any number is worth 100x that number! EG, [3][3][3] = 300 points."+nL);
						 output.append("	~The only exception to this rule is [1][1][1], which is worth 1000 points."+nL);
						 output.append("Four-of-a-kind scores twice what 3-of-a-kind is worth." +nL);
						 output.append("	~EG [1][1][1][1] = 2000, and [4][4][4][4] = 800."+nL);
						 output.append("And five-of-a-kind is worth twice what four-of-a-kind would be worth!"+nL+nL);
						 output.append("Furthermore, if any dice in a roll don't contribute to the score, you could choose to reroll the non-scoring die."+nL);
						 output.append("	~For example, in [1][1][1][4][6], you could choose to re-roll the [4][6]."+nL);
						 output.append("	~But beware! If rerolling dice doesn't *improve* your score, you'll lose all points gained that round!"+nL);
						 output.append("Lastly, if *every* dice thrown contributes to the score, then you can re-roll all five to try and gain even more points."+nL);
						 output.append("	~Again, beware! If you ever fail to gain points in a throw, you'll lose all points gained in that series of throws."+nL);
						 output.append("Good luck!"+nL+nL);
						 break;

				case 999:	output.append("Thanks for playing!"+nL); //This kills the program.
						on=false;
						break;
				}
			}
			}
		
		else{
			if(userSelection.equals("b")){ //Hit 'b' at the startup menu to enter Sim mode.
				
				output.append(nL+"How many experiments would you like to loop?"+nL+nL); //Hope you brought a packed lunch if you enter 20m+.
				userSelection = null;
				
				while(userSelection==null){
				}
						
				int target = Integer.parseInt(userSelection);

				for(int i = 0; i<target; i++){
					
					artificialTakeTurn(); 
					
					lastGo.clear();
					output.setText(  ""+((100*i)/target)     ); //This makes the current '%' of how far through the sims you are appear on the GUI. Flickery from all the updates, but visible.
				}
				output.setText("Results file written!");
				try {
					fileWrite();
				} catch (IOException e) {
					e.printStackTrace();
				}
				}
				
				
				
			}
		
		}
	
	private static void createAndShowGUI() { //Initialises and "Lego"s together all the GUI sections.
	
		window = new JFrame("Ten Thousand");
		window.setVisible(true);
		window.setSize(900, 750); //Huge. Might dangle off the screen of netbooks or older machines, but it's resizeable anyway.
		window.setLayout(new BorderLayout(5, 5)); //Little margin between input and output.
		window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		southWindow = new JPanel();
		southWindow.setLayout(new BorderLayout());
		
		inputLabel = new JLabel("  Enter options here!  ");
		input = new JTextField();
		input.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				userSelection = input.getText();
				input.setText(null);
			}
		});
		
		southWindow.add(inputLabel, BorderLayout.WEST); //South window goes to the south, remember? For inputty stuff.
		southWindow.add(input, BorderLayout.CENTER);
		
		output = new JTextArea();
		jsp = new JScrollPane(output, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); //Tidier than always having both, or starting with no V-bar.
		jsp.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener(){
			public void adjustmentValueChanged(AdjustmentEvent e){
								output.selectAll(); //Sneaky method to set the scrollbar to the bottom every time the user does, well, anything.
													//Otherwise they'd have to scroll down every time they enter a decision, which was a MAJOR annoyance.
			}});
		
		output.setEditable(false); //Don't want the output getting messed up. But it is highlightable, and can be Ctrl+A'd, copied etc. Just not removed!
		
		window.add(jsp, BorderLayout.CENTER);
		window.add(southWindow, BorderLayout.SOUTH);		
		}
		
	private static void artificialTakeTurn(){ //This method, and the two just below, control how the game operates when running simulations.
											//In essence, the code is the same as the "take turn" code from regular play, but with decisions overwritten.
											//Oh, and results are logged in a 2D array periodically too. But that's all that's different!
		vals = d.rollEach();
		theVeryLatestScore = scorerAlgorithm(valueTransposer(vals));
		if(theVeryLatestScore==0){
			attempts[4][0] = attempts[4][0]+1;
		}
		else{
			attempts[4][0] = attempts[4][0]+1;
			earnings[4][0] = earnings[4][0]+theVeryLatestScore;
		}
		totalScore = totalScore+theVeryLatestScore;
		lastGo =  (ArrayList<Integer>) vals.clone();
		vals.clear();
		
		canReroll = true;
		if(theVeryLatestScore==0){
			canReroll=false;
		}
		
		if(diceToReroll.size()>0){
			diceToReroll.clear();
		}
		
		if(theVeryLatestScore>0 && canReroll==true && worthlessDice().size()>0){
			artificialWhatToDoWhenRerolling();
		}
		else{
			if(worthlessDice().size()==0){
		
			artificialAllScoreRerollCase();
		}
		}
	}

	private static void artificialAllScoreRerollCase() {//Method only used when the game is "playing itself". Manages all-dice-score scenario.
	
		Random r = new Random();
		lastGo.clear();
		for(int i = 0; i<5; i++){
			lastGo.add((r.nextInt(6)+1));
		}
		
		int snap = theVeryLatestScore;
		
		int bonusScore = scorerAlgorithm(valueTransposer(lastGo));
		
		if(bonusScore>0){
			attempts[4][snap/50] = attempts[4][snap/50]+1;
			earnings[4][snap/50] = earnings[4][snap/50]+bonusScore;
			totalScore = totalScore-theVeryLatestScore;
			theVeryLatestScore = theVeryLatestScore+bonusScore;
			totalScore = totalScore+theVeryLatestScore;
			
			if(worthlessDice().size()==0){
				artificialAllScoreRerollCase();
			}
			else{
			artificialWhatToDoWhenRerolling();
			}
		}
		else{
			attempts[4][snap/50] = attempts[4][snap/50]+1;
			earnings[4][snap/50] = earnings[4][snap/50]-theVeryLatestScore;
			canReroll = false;
			punishLoser = true;
		}
	}
	
	private static void artificialWhatToDoWhenRerolling() {	//Method only used when the game is "playing itself". Manages the actions performed when rerolling some die.
		
		int many = worthlessDice().size();
		removeUnwantedDice();
		rerollSome(diceToReroll);
		int snap = theVeryLatestScore;
		
		if(!(scorerAlgorithm(valueTransposer(diceToReroll))>0)){ //This punishes you if your reroll doesn't score.
			if(totalScore>0){
				totalScore = totalScore-theVeryLatestScore;
				attempts[many-1][snap/50] = attempts[many-1][snap/50]+1;
				earnings[many-1][snap/50] = earnings[many-1][snap/50]-theVeryLatestScore;
			}
			if(totalScore<0){
				totalScore = 0;
			}
		}
		else{
			totalScore = totalScore-theVeryLatestScore;
			theVeryLatestScore = theVeryLatestScore+(scorerAlgorithm(valueTransposer(diceToReroll)));
			totalScore = totalScore+theVeryLatestScore;
			attempts[many-1][snap/50] = attempts[many-1][snap/50]+1;
			earnings[many-1][snap/50] = earnings[many-1][snap/50]+scorerAlgorithm(valueTransposer(diceToReroll));
			
			for(int j : diceToReroll){		
				lastGo.add(j);
			}
			if(worthlessDice().size()==0){
				diceToReroll.clear();
				artificialAllScoreRerollCase();
			}
			else{
				diceToReroll.clear();
				artificialWhatToDoWhenRerolling();
			}
		}
	}

	private static void specialAllScoreRerollCase() {//This complex method deals with the occasional scenario of every one of the player's die contributing to the score. 
		
		Random r = new Random();
		lastGo.clear();
		for(int i = 0; i<5; i++){
			lastGo.add((r.nextInt(6)+1));
		}

		
		int bonusScore = scorerAlgorithm(valueTransposer(lastGo));
		
		output.append(nL+"The brand new roll is "+lastGo+", which is worth "+scorerAlgorithm(valueTransposer(lastGo))+" points."+nL+nL);
		
		if(bonusScore>0){
			output.append("Since this is, taking the previous 5 dice into account, an improvement upon your overall score, your potential score has been updated!"+nL);
			totalScore = totalScore-theVeryLatestScore;
			theVeryLatestScore = theVeryLatestScore+(scorerAlgorithm(valueTransposer(lastGo)));
			totalScore = totalScore+theVeryLatestScore;
			
			if(worthlessDice().size()==0){
				output.append("Since every value you've rolled in this series of throws has been worth something, you can reroll them all if you want."+nL);
				output.append("Want to re-roll all 5? (y/n)"+nL+nL);
				userSelection = null;
				while(userSelection==null){
				}
				
				String ch = userSelection;
				if(ch.equals("y")){
					diceToReroll.clear();
				specialAllScoreRerollCase();
				}
				else{
					output.append("Of course."+nL+nL);
					canReroll = false;
				}
			}
			
				else if(worthlessDice().size()>0){
			output.append("Want to keep rolling? (y/n)"+nL);
			
			userSelection = null;
			while(userSelection==null){
			}
		
			if(userSelection.equals("y")){
				userSelection = null;
				if(theVeryLatestScore>maxScorein1Turn){
					maxScorein1Turn = theVeryLatestScore;
				}
				winTest();
				whatToDoWhenRerolling();
			}
			else{
				output.append("Your total score has been updated."+nL+nL);
				if(theVeryLatestScore>maxScorein1Turn){
					maxScorein1Turn = theVeryLatestScore;
				}
				winTest();
			}
		}
		}
		
		else{
			output.append("Since the 5-dice reroll was worthless, you have lost all point accumulated through the prior sequence of rolling 5 dice."+nL);
			output.append("Too bad!"+nL+nL);
		}
	}
	
	private static void winTest() {//This method's called every so often to see if 10k points have been attained, at which point the prog. halts and the user sees some stats.
		if(totalScore>=10000){
		output.append("Congratulations! You've attained 10,000 points, and the game's now over."+nL);
		output.append("Here's some statistics about your game."+nL);
		output.append("Turns taken: "+turnsTakenThusFar+nL);
		double avgTurn = totalScore/turnsTakenThusFar;
		output.append("Average points per turn: "+avgTurn+nL);
		output.append("Greatest score in one turn: "+maxScorein1Turn+nL);
		on=false;
		}
	}
	
	private static ArrayList<Integer> worthlessDice(){  //By removing die in turn from the player's hand, this method determined which are worthless WRT the current score.
		
		ArrayList<Integer> eachWorthlessNumber = new ArrayList<Integer>();
		
		for(int i =0; i<lastGo.size(); i++){
			ArrayList<Integer> testForWorth = new ArrayList<Integer>();
			testForWorth = (ArrayList<Integer>) lastGo.clone();
			int pre = scorerAlgorithm(valueTransposer(testForWorth));
			int proposedWorthlessNumber;
			proposedWorthlessNumber = testForWorth.remove(i);
			int post = scorerAlgorithm(valueTransposer(testForWorth));
			if(pre==post){
			eachWorthlessNumber.add(proposedWorthlessNumber);
			}	
		}
		return eachWorthlessNumber;
	}
	
	public static void whatToDoWhenRerolling(){  //Subroutines called when a user requests that their "useless" die are rerolled.
		removeUnwantedDice();
		rerollSome(diceToReroll);
		if(!(scorerAlgorithm(valueTransposer(diceToReroll))>0)){
			output.append("Since the rerolled dice aren't worth any additional points, your turn is now over, and any points scored this round are lost."+nL+nL);
			if(totalScore>0){
				totalScore = totalScore-theVeryLatestScore;
			}
			if(totalScore<0){
				totalScore = 0;
			}
		}
		else{
			userSelection = null;
			output.append("Since the rerolled dice are worth "+(scorerAlgorithm(valueTransposer(diceToReroll)))+" points, which is more overall than your earlier roll, your score has been updated!"+nL+nL);
			totalScore = totalScore-theVeryLatestScore;

			theVeryLatestScore = theVeryLatestScore+(scorerAlgorithm(valueTransposer(diceToReroll)));
			
			if(theVeryLatestScore>maxScorein1Turn){
				maxScorein1Turn = theVeryLatestScore;
			}
			totalScore = totalScore+theVeryLatestScore;
			
			for(int j : diceToReroll){
				lastGo.add(j);	
			}
			
			if(worthlessDice().size()==0){
				output.append("Since every value you've rolled in this series of throws has been worth something, you can reroll them all if you want."+nL);
				output.append("Want to re-roll all 5? (y/n)"+nL+nL);
				userSelection = null;
				while(userSelection==null){
				}
				if(userSelection.equals("y")){
					diceToReroll.clear();
					specialAllScoreRerollCase();
				}
				else{
					output.append("Of course."+nL+nL);
				}
			}
			
			else{
			output.append("Want to keep rolling to try and improve this score? (y/n)"+nL+nL);
			userSelection = null;
			while(userSelection==null){
			}
			if(userSelection.equals("y")){
				diceToReroll.clear();
				whatToDoWhenRerolling();
			}
			else{
				output.append("That's this turn over; then."+nL+nL);
				}
			}
		}
		winTest();
	}
		
	public static void rerollSome (ArrayList<Integer> x){  //Adds random numbers to a handful of dice until there's 5. Used after discarding useless die when rerolling!
		
		ArrayList<Integer> news = new ArrayList<Integer>();
		Random r = new Random();
		
		for(int i = 0; i<x.size(); i++){
			news.add((r.nextInt(6)+1));
		}
		diceToReroll = (ArrayList<Integer>) news.clone();
		
		output.append(nL+"Some new numbers have been added. Your die now read "+lastGo+diceToReroll+"."+nL+nL);
		}
	
	public static int scorerAlgorithm(int[] transposed){ //Scores a dice roll by strict hierarchy. "Transposed" parameter is explained below!

		int scoreThisRound = 0;
		
		if(transposed[0]>0 && transposed[0]<3){
			scoreThisRound = scoreThisRound+(100*transposed[0]);
		}
		if(transposed[4]>0 && transposed[4]<3){
			scoreThisRound = scoreThisRound+(50*transposed[4]);
		}
		
		for(int i = 1; i<6; i++){
			if(transposed[i]==3){
				scoreThisRound = scoreThisRound+(100*(i+1));
			}
		}
		for(int i = 1; i<6; i++){
			if(transposed[i]==4){
				scoreThisRound = scoreThisRound+(200*(i+1));
			}
		}
		
		for(int i = 1; i<6; i++){
			if(transposed[i]==5){
				scoreThisRound = scoreThisRound+(400*(i+1));
			}
		}
		
		if(transposed[0]==3){
			scoreThisRound = scoreThisRound+1000;
		}
		
		if(transposed[0]==4){
			scoreThisRound = scoreThisRound+2000;
		}
		
		if(transposed[0]==5){
			scoreThisRound = scoreThisRound+4000;
		}
		
		return scoreThisRound;	
	}

	public static void removeUnwantedDice(){  //Removes all dice that don't contribute to the current score.
		
		ArrayList<Integer> toReroll = worthlessDice();
		
		output.append("The "+toReroll.size()+" values "+toReroll+" have been trashed and rerolled!"+nL+nL);
		
		for(int i = 0; i<toReroll.size(); i++){
			if(lastGo.get(0)==toReroll.get(i)){
				diceToReroll.add(lastGo.get(0));
				lastGo.remove(0);
			}
			else{
				if(lastGo.get(1)==toReroll.get(i)){
					diceToReroll.add(lastGo.get(1));
					lastGo.remove(1);
				}
				else{
					if(lastGo.get(2)==toReroll.get(i)){
						diceToReroll.add(lastGo.get(2));
						lastGo.remove(2);
					}
					else{
						if(lastGo.get(3)==toReroll.get(i)){
							diceToReroll.add(lastGo.get(3));
							lastGo.remove(3);
						}
						else{
							if(lastGo.get(4)==toReroll.get(i)){
								diceToReroll.add(lastGo.get(4));
								lastGo.remove(4);
							}	
						}
					}
				}
			}
		}
	}
	
	public static int[] valueTransposer(ArrayList<Integer> values){  //This essential method turns a dice roll into a list of quantities of each value. Essential for scoring.

		int[] howMany = new int[6];
		
		for(int i = 0; i<values.size(); i++){
			howMany[(values.get(i)-1)] =    howMany[(values.get(i)-1)]+1;
		}
		
		return howMany;
	}
	
	public static void fileWrite() throws IOException{ //Upon completion of Simulation Mode, writes a 'guide' for players based on situations encountered.

			File file = new File("10kAIresults.txt");
			if(!file.exists()){
				try {
					file.createNewFile();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
			try {
				FileWriter fw = new FileWriter(file.getAbsoluteFile());
				BufferedWriter bw = new BufferedWriter(fw);
			
				
//This body of code works out turn-based average point gain/loss. Unnecessary for solution, but might be handy someday.
//				for(int x = 0; x<5; x++){
//					for(int y = 0; y<201; y++){
//						float temp = earnings[x][y];
//						float temp2 = attempts[x][y];
//						if(temp2>0){
//						earnings[x][y] = (temp/temp2);
//						}
//					}
//				}
				
				
				bw.write("The grid below represents the latest calculation of the winning strategy for Ten Thousand.");
				bw.newLine();
				bw.write("Using the strategy is simple - when you have points in hand equal to a number on the Y-axis,");
				bw.newLine();
				bw.write("and a number of die left to roll indicated across the X-axis, then the corresponding cell's contents tell you whether you should roll or not with a 'Y'or 'N' respectively.");
				bw.newLine();
				
				bw.newLine();
				bw.newLine();
				bw.write("Pts Held:	1		2		3		4		5"); //Spacing my be off due to tabs; depends on the program you read the file with, and font etc.
																		//But this is about as close to a general format as I think you can achieve.
				bw.newLine();
				
				for(int i = 0; i<201; i++){
					String work = "";
					String fiveDiceAssertion;
					String fourDiceAssertion;
					String threeDiceAssertion;
					String twoDiceAssertion;
					String oneDiceAssertion;
					
					if(earnings[0][i]>0){
						oneDiceAssertion = "Y"; //Ys denote good moves, and Ns bad ones. Yes and No, get it?
					}
					else{
						oneDiceAssertion = "N";
					}
					if(earnings[1][i]>0){
						twoDiceAssertion = "Y";
					}
					else{
						twoDiceAssertion = "N";
					}
					if(earnings[2][i]>0){
						threeDiceAssertion = "Y";
					}
					else{
						threeDiceAssertion = "N";
					}
					if(earnings[3][i]>0){
						fourDiceAssertion = "Y";
					}
					else{
						fourDiceAssertion = "N";
					}
					if(earnings[4][i]>0){
						fiveDiceAssertion = "Y";
					}
					else{
						fiveDiceAssertion = "N";
					}
					
					work = work+(i*50)+"	["+oneDiceAssertion+"]		["+twoDiceAssertion+"]		["+threeDiceAssertion+"]		["+fourDiceAssertion+"]		["+fiveDiceAssertion+"]";
					bw.write(work);
					bw.newLine();
					
					
//					This body of code wrote the values of positivity to the text file instead of Y and N.
//					But knowing the polarity of the number is more what the solution is about, than knowing the number itself. So I edited it out.
//					work = work+(i*50)+"	["+earnings[0][i]+"]		["+earnings[1][i]+"]		["+earnings[2][i]+"]		["+earnings[3][i]+"]		["+earnings[4][i]+"]";
//					bw.write(work);
//					bw.newLine();
					
				}
					bw.write("===================================================================================");
					bw.newLine();
					bw.close();
			}
			finally{
					//finally was a requirement syntactically, but I don't need it.
			}
		
	}
}